package com.welica.wat.aspect;

import java.lang.reflect.Method;
import java.util.Arrays;

import javax.annotation.Resource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

import com.welica.wat.impl.RedisLock;
import com.welica.wat.stragety.DistributeLockStrategy;
import com.welica.wat.stragety.annotation.DistributeLock;

/**
* @ClassName: DistributeLockAspect
* @Description: 基于redssion实现分布式锁，AOP切面声明
* @author weiyongpeng
* @date 2024年11月1日 下午8:45:29
 */
@Component
@Aspect
@ConditionalOnBean(RedisLock.class)
public class RedissionDistributeLockAspect {
	
	private static final Logger log = LoggerFactory.getLogger(RedissionDistributeLockAspect.class);
    
    @Resource
    private RedisLock distributeLock;
    
    /**
     * @annotation 中的路径表示拦截特定注解
     */
    @Pointcut("@annotation(com.welica.wat.stragety.annotation.DistributeLock)")
    public void lockAop() {
    }
    
    @Around(value = "lockAop()")
    public Object setDistributeLock(ProceedingJoinPoint pjp) throws Throwable {
        // 解析参数
        Method method = resolveMethod(pjp);
        DistributeLock annotation = method.getAnnotation(DistributeLock.class); // 拦截方法上的注解
        String params = Arrays.toString(pjp.getArgs()); // 获取方法参数
        String lockName = annotation.lockName(); // 获取锁的key
        if(!"[]".equals(params)){
            //获取锁
            lockName = annotation.lockName() + "_" + params.replace("[","").replace("]","");
        }
        log.info("the current thread is {} lockname is {}",Thread.currentThread().getName(), lockName);

        boolean b = distributeLock.lock(lockName,annotation.expireTime(),false);

        if(annotation.isSpin() && b==false){ //如果无法获取锁
            b = distributeLock.lock(lockName,annotation.expireTime(),true);
        }

        //执行业务
        if(!b){
            throw new IllegalAccessError("当前线程获取分布式锁失败");
        }
        log.info("the current thread is {} obtain lock lockname is {}",Thread.currentThread().getName(), lockName);
        Object ret = pjp.proceed();//执行业务逻辑
        //释放锁
        distributeLock.unLock(lockName);
        log.info("the current thread is {} release lock lockname is {}",Thread.currentThread().getName(), lockName);
        return ret;
    }

    private Method resolveMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = pjp.getTarget();
        return  target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    }

}
